package gui;

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Dimension;
import java.awt.List;
import java.awt.Scrollbar;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.ToolTipManager;

import util.Util;

import core.CalculationException;
import core.DmuList;
import core.Optimization;
import core.PdmOptimization;
import facilitator.SolutionProvider;

import net.sourceforge.chart2d.Chart2DProperties;
import net.sourceforge.chart2d.Dataset;
import net.sourceforge.chart2d.GraphChart2DProperties;
import net.sourceforge.chart2d.GraphProperties;
import net.sourceforge.chart2d.LBChart2D;
import net.sourceforge.chart2d.LegendProperties;
import net.sourceforge.chart2d.MultiColorsProperties;
import net.sourceforge.chart2d.Object2DProperties;

public class PdmFrame extends JFrame implements ActionListener, AdjustmentListener{

	
	/**
	 * 
	 */
	private static final long serialVersionUID = 8294028497125868589L;
	
	private DmuList dmuList;
	private SolutionProvider provider;
	private double[] absUrmWeights;
	private int currentTransition = 0;
	
	private JPanel chartPanel = new JPanel();
	private LBChart2D chart;
	private JPanel chartNorth;
	private JPanel chartSouth;
	private TextField chartStatus;
	private TextField alphaValue;
	private TextField distanceValue;
	private TextField objectiveValue;
	private Scrollbar scrollBar;
	private JSpinner[] outputSpinner;
	List chartDmuList;
	
	
	public PdmFrame(DmuList dmuList, double[] absUrmWeights) {
		this(dmuList);
		this.absUrmWeights = absUrmWeights;
	}
	public PdmFrame(DmuList dmuList) {
		this.dmuList = dmuList;
		this.dmuList.setObjectiveDmu(0);
		this.provider = new SolutionProvider(dmuList);
		this.outputSpinner = new JSpinner[dmuList.outputSize];
	}
	public void initialize(){		
		this.setTitle("PDM Chart window");
		this.addWindowListener (
			      new WindowAdapter() {
			        public void windowClosing (WindowEvent e) {
			          destroy();
			    } } );
		chartPanel.setLayout(new BorderLayout());
		
		chartNorth = new JPanel();
		chartNorth.setLayout(new BoxLayout(chartNorth, BoxLayout.X_AXIS));
		chartDmuList = new List(1);
		for(int i = 1;i <=this.dmuList.size();i++){
			chartDmuList.add(String.valueOf(i), i-1);
		}
		chartDmuList.select(dmuList.getObjectiveDmu());
		chartNorth.add(chartDmuList);
		
		//todo: do some formatting
		for(int i = 0;i <this.dmuList.outputSize;i++){
			JSpinner spin = new JSpinner();
			if(this.absUrmWeights != null){
				spin.setValue(this.absUrmWeights[i]);
			}
			else{
				spin.setValue(i+1);
			}
			spin.setToolTipText("Set weight for output " + i+1);
			outputSpinner[i] = spin;
			chartNorth.add(spin);
		}
		
		
		Button chartRecalculate = new Button("Calculate");
		chartRecalculate.setActionCommand("RECALCULATE");
		chartRecalculate.addActionListener(this);
		chartNorth.add(chartRecalculate);
		
		chartSouth = new JPanel();
		chartSouth.setLayout(new BoxLayout(chartSouth, BoxLayout.X_AXIS));
		chartStatus = new TextField("Ready");
		chartStatus.setEditable(false);
		alphaValue = new TextField("Alpha");
		alphaValue.setEditable(false);
		distanceValue = new TextField("Distance");
		distanceValue.setEditable(false);
		objectiveValue = new TextField("Efficiency");
		objectiveValue.setEditable(false);
		chartSouth.add(chartStatus);
		chartSouth.add(objectiveValue);
		chartSouth.add(alphaValue);
		chartSouth.add(distanceValue);
		
		chartPanel.add(chartNorth, BorderLayout.NORTH);
		chartPanel.add(chartSouth, BorderLayout.SOUTH);
		
		this.drawInitialChart();
		this.setContentPane(chartPanel);
		this.pack();
		this.setVisible(true);
	}
	private void drawInitialChart() {
		try {
			this.initChart(SolutionProvider.getRelOutputWeights(provider.getDeaOptimization()));
			chartPanel.add(chart, BorderLayout.CENTER);
		} catch (CalculationException e) {
			e.printStackTrace();
		}
	}
	//urmVars changed, reCalc Button pressed
	private void reCalculate(){
		double alpha = 0.0;
		double[] absUrmWeights = new double[outputSpinner.length];
		for(int i =0; i< outputSpinner.length;i++){
			absUrmWeights[i] = Double.parseDouble(outputSpinner[i].getValue().toString());
		}
		//calculate DEA for new DMU
		this.dmuList.setObjectiveDmu(chartDmuList.getSelectedIndex());
		Optimization deaOpt = provider.getDeaOptimization();
		provider.setOptimizationDirections(deaOpt, absUrmWeights);
		PdmOptimization pdmOpt = provider.getPdmOptimization(alpha, absUrmWeights);
		
		try {
			this.updateChartData(SolutionProvider.getRelOutputWeights(deaOpt),SolutionProvider.getRelWeights(absUrmWeights), SolutionProvider.getRelOutputWeights(pdmOpt));
			this.chartStatus.setText("Dmu: " + chartDmuList.getSelectedItem());
			this.alphaValue.setText("Alpha: 0");
			this.distanceValue.setText("Distance: " + Util.truncate(pdmOpt.getProfileDistance(), 5));
			this.objectiveValue.setText("Efficiency: " + Util.truncate(pdmOpt.getOptimizationObjective(), 5));
		} catch (CalculationException e) {
			e.printStackTrace();
		}
		chart.repaint();
		provider.calcTransitionList(absUrmWeights);
		this.initScrollbar();
	}
	private void initScrollbar(){
		if(scrollBar == null){
			this.scrollBar = new Scrollbar(Scrollbar.VERTICAL, 0, 1, 1, provider.getTransitionList().size()+1);
			this.scrollBar.addAdjustmentListener(this);
			chartPanel.add(scrollBar, BorderLayout.EAST);
			this.pack();
		}
		else{
			this.scrollBar.setMaximum(provider.getTransitionList().size()+1);
			this.scrollBar.setValue(0);
			this.currentTransition = 0;
		}
		scrollBar.repaint();
	}
	//urm stays, alpha changed (scrollbar moved)
	private void refreshChart(int adjustmentDirection){
		if(adjustmentDirection==1){
			currentTransition++;
		}
		else{
			currentTransition--;
		}
		try {
			this.updateChartData(SolutionProvider.getRelOutputWeights(provider.getTransitionList().get(currentTransition)));
			this.alphaValue.setText("Alpha: " + Util.truncate(provider.getTransitionList().get(currentTransition).getAlpha(), 5));
			this.distanceValue.setText("Distance: " + Util.truncate(provider.getTransitionList().get(currentTransition).getProfileDistance(), 5));
			this.objectiveValue.setText("Efficiency: " + Util.truncate(provider.getTransitionList().get(currentTransition).getOptimizationObjective(), 5));
		} catch (CalculationException e) {
			e.printStackTrace();
		}
		chart.repaint();
	}
	private void destroy() {
		this.dispose();
	}
	@Override
	public void actionPerformed(ActionEvent e) {
		if(e.getActionCommand() == "RECALCULATE"){
			this.reCalculate();
		}
	}
	@Override
	public void adjustmentValueChanged(AdjustmentEvent arg0) {
		this.refreshChart(arg0.getAdjustmentType());
	}
	private void updateChartData(double[] deaValues, double[] urmValues, double[] pdmValues){
		
		Dataset dataset = chart.getDataset(0);
		LegendProperties legendProps = chart.getLegendProperties();
		String[] legendLabels;
		
		//resize dataset
		dataset.setSize(3, urmValues.length, 1);
		
		//set urmValues
		for (int i = 0; i < deaValues.length; i++) {
			dataset.set(0, i, 0, Float.parseFloat(
					String.valueOf(deaValues[i])));
		}
		
		//set urmValues
		for (int i = 0; i < urmValues.length; i++) {
			dataset.set(1, i, 0, Float.parseFloat(
					String.valueOf(SolutionProvider.getRelWeights(urmValues)[i])));
		}
		//set pdmValues
		for (int i = 0; i < pdmValues.length; i++) {
			dataset.set(2, i, 0, Float.parseFloat(
					String.valueOf(pdmValues[i])));
		}
		
		//set new legenddata
		legendLabels = new String[]{"DEA", "URM", "PDM"};		
	    legendProps.setLegendLabelsTexts (legendLabels);
	}
	private void updateChartData(double[] pdmValues){
		
		Dataset dataset = chart.getDataset(0);
		
		//set new pdmValues
		for (int i = 0; i < pdmValues.length; i++) {
			dataset.set(2, i, 0, Float.parseFloat(
					String.valueOf(pdmValues[i])));
		}
	}
	private void initChart(double[] deaValues) {

		// Configure object properties
		Object2DProperties object2DProps = new Object2DProperties();
		object2DProps.setObjectTitleText("PDM");

		// Configure chart properties
		Chart2DProperties chart2DProps = new Chart2DProperties();
		chart2DProps.setChartDataLabelsPrecision(-3);

		// Configure legend properties
		LegendProperties legendProps = new LegendProperties();
		
		// Configure graph chart properties
		GraphChart2DProperties graphChart2DProps = new GraphChart2DProperties();

		String[] labelsAxisLabels = new String[deaValues.length];
		labelsAxisLabels[0] = "controlling and reporting";
		labelsAxisLabels[1] = "accounting";
		labelsAxisLabels[2] = "logistics";
		labelsAxisLabels[3] = "purchasing";
		labelsAxisLabels[4] = "needs of local divisions";
		labelsAxisLabels[5] = "services and engineering";
		labelsAxisLabels[6] = "sales";
		labelsAxisLabels[7] = "business mgmt";
		
		graphChart2DProps.setLabelsAxisLabelsTexts(labelsAxisLabels);
		graphChart2DProps.setLabelsAxisTitleText("Outputs");
		graphChart2DProps.setNumbersAxisTitleText("Value");

		// Configure graph properties
		GraphProperties graphProps = new GraphProperties();
		//graphProps.setGraphLinesThicknessModel(3);
		//graphProps.setGraphBarsExistence(false);
		//graphProps.setGraphLinesExistence(true);
		//graphProps.setGraphAllowComponentAlignment (true);
	    graphProps.setGraphBarsRoundingRatio (0f);
		graphProps.setGraphOutlineComponentsExistence(true);
		//graphProps.setGraphAllowComponentAlignment(true);

		String[] legendLabels;
		Dataset dataset = new Dataset(1, deaValues.length, 1);
		for (int i = 0; i < deaValues.length; i++) {
			dataset.set(0, i, 0, Float.parseFloat(String.valueOf(deaValues[i])));
		}
		legendLabels = new String[]{"DEA"};
		
	    legendProps.setLegendLabelsTexts (legendLabels);
	    
		// Configure graph component colors
		MultiColorsProperties multiColorsProps = new MultiColorsProperties();

		// Configure chart
		chart = new LBChart2D();
		chart.setObject2DProperties(object2DProps);
		chart.setChart2DProperties(chart2DProps);
		chart.setLegendProperties(legendProps);
		chart.setGraphChart2DProperties(graphChart2DProps);
		chart.addGraphProperties(graphProps);
		chart.addDataset(dataset);
		chart.addMultiColorsProperties(multiColorsProps);

		// Optional validation: Prints debug messages if invalid only.
		if (!chart.validate(false))
			chart.validate(true);
		
		chart.setPreferredSize(new Dimension(400,200));
		// <-- End Chart2D configuration -->
		chart.repaint();
	}
}
